﻿using Microsoft.Xna.Framework;
using System;
using Terraria;
using Terraria.ID;
using Terraria.ModLoader;
using WorseGame.Common.Configs;
using WorseGame.Common.Systems;

namespace WorseGame.Common.GlobalNPCs
{
    public class WorseNPC : GlobalNPC
    {
        private static bool[] hasSplit = new bool[Main.maxNPCs];
        public override bool InstancePerEntity => true;
        protected override bool CloneNewInstances => true;       
        private static bool IsWallPhasingNPC(NPC npc)
        {
            return npc.noTileCollide && !npc.boss && !npc.friendly;
        }
        private static bool IsInsideSolidTile(NPC npc)
        {
            Rectangle npcRect = npc.getRect();
            int startX = (int)(npcRect.Left / 16f);
            int endX = (int)(npcRect.Right / 16f);
            int startY = (int)(npcRect.Top / 16f);
            int endY = (int)(npcRect.Bottom / 16f);
            for (int x = startX; x <= endX; x++)
            {
                for (int y = startY; y <= endY; y++)
                {
                    if (WorldGen.InWorld(x, y) && Main.tile[x, y].HasTile && Main.tileSolid[Main.tile[x, y].TileType] && !Main.tileSolidTop[Main.tile[x, y].TileType])
                    {
                        return true;
                    }
                }
            }
            return false;
        }
        public override bool? CanBeHitByItem(NPC npc, Player player, Item item)
        {
            if (NPCConfig.Instance.WallNPCinvincible && IsWallPhasingNPC(npc) && IsInsideSolidTile(npc))
            {
                return false;
            }
            return base.CanBeHitByItem(npc, player, item);
        }
        public override bool? CanBeHitByProjectile(NPC npc, Projectile projectile)
        {
            if (NPCConfig.Instance.WallNPCinvincible && IsWallPhasingNPC(npc) && IsInsideSolidTile(npc))
            {
                return false;
            }
            return base.CanBeHitByProjectile(npc, projectile);
        }
        public override bool CanBeHitByNPC(NPC npc, NPC attacker)
        {
            if (NPCConfig.Instance.WallNPCinvincible && IsWallPhasingNPC(npc) && IsInsideSolidTile(npc))
            {
                return false;
            }
            return base.CanBeHitByNPC(npc, attacker);
        }
        public override void ModifyActiveShop(NPC npc, string shopName, Item[] items)
        {
            if (NPCConfig.Instance.NPCShopRandomDeleteItem)
            {
                Random random = new();
                for (int i = 0; i < items.Length; i++)
                {
                    if (random.Next(2) == 0 && items[i] != null && !items[i].IsAir)
                    {
                        items[i].TurnToAir();
                    }
                }
            }            
        }
        public override void OnHitByItem(NPC npc, Player player, Item item, NPC.HitInfo hit, int damageDone)
        {
            if (NPCConfig.Instance.NPCSplit && !npc.boss)
            {
                TrySplit(npc);
            }
        }
        public override void OnHitByProjectile(NPC npc, Projectile projectile, NPC.HitInfo hit, int damageDone)
        {
            if (NPCConfig.Instance.NPCSplit && !npc.boss)
            {
                TrySplit(npc);
            }
        }
        public override void OnKill(NPC npc)
        {
            if (NPCConfig.Instance.NPCSplit && !npc.boss)
            {
                if (npc.whoAmI < hasSplit.Length)
                {
                    hasSplit[npc.whoAmI] = false;
                }
            }
        }
        private static void TrySplit(NPC npc)
        {
            if (!hasSplit[npc.whoAmI] && npc.life <= npc.lifeMax / 2)
            {
                hasSplit[npc.whoAmI] = true;

                if (Main.netMode != NetmodeID.MultiplayerClient)
                {
                    SplitNPC(npc);
                }
            }
        }
        private static void SplitNPC(NPC original)
        {
            int newNPC = NPC.NewNPC(original.GetSource_FromAI(), (int)original.Center.X, (int)original.Center.Y, original.type, ai3: 1);
            if (newNPC < Main.maxNPCs)
            {
                NPC clone = Main.npc[newNPC];
                clone.lifeMax = original.lifeMax / 2;
                clone.life = clone.lifeMax;
                clone.scale = original.scale * 0.75f;
                clone.width = (int)(original.width * 0.75f);
                clone.height = (int)(original.height * 0.75f);
                clone.damage = (int)(original.damage * 0.8f);
                clone.defense = (int)(original.defense * 0.8f);
                for (int i = 0; i < 10; i++)
                {
                    Dust.NewDust(original.position, original.width, original.height, DustID.Blood, Main.rand.NextFloat(-3f, 3f), Main.rand.NextFloat(-3f, 3f));
                }
                if (Main.netMode == NetmodeID.Server)
                {
                    NetMessage.SendData(MessageID.SyncNPC, -1, -1, null, newNPC);
                }
            }
        }

        public override void ApplyDifficultyAndPlayerScaling(NPC npc, int numPlayers, float balance, float bossAdjustment)
        {
            if (MultiplayerModeConfig.Instance.DamageMax)
            {
                npc.damage *= (int)(numPlayers * 2 * bossAdjustment);
            }
            if (MultiplayerModeConfig.Instance.DefenseMax)
            {
                npc.defense *= (int)(numPlayers * 2 * bossAdjustment);
            }
            if (MultiplayerModeConfig.Instance.LifeMax)
            {
                npc.lifeMax *= (int)(numPlayers * 2 * bossAdjustment);
            }
        }
        public override void EditSpawnRate(Player player, ref int spawnRate, ref int maxSpawns)
        {
            if (MultiplayerModeConfig.Instance.SpawnRate)
            {
                spawnRate *= Main.CurrentFrameFlags.ActivePlayersCount;
                maxSpawns *= Main.CurrentFrameFlags.ActivePlayersCount;
            }
            if (NPCConfig.Instance.NPCSplit)
            {
                if (hasSplit.Length < Main.maxNPCs)
                {
                    bool[] newArray = new bool[Main.maxNPCs];
                    for (int i = 0; i < hasSplit.Length; i++)
                    {
                        newArray[i] = hasSplit[i];
                    }
                    hasSplit = newArray;
                }
            }
        }
        public override bool? DrawHealthBar(NPC npc, byte hbPosition, ref float scale, ref Vector2 position)
        {
            if (NPCConfig.Instance.HideHealthBar)
            {
                return false;
            }
            return base.DrawHealthBar(npc, hbPosition, ref scale, ref position);
        }
        public override bool PreKill(NPC npc)
        {
            if (NPCConfig.Instance.NPCDropsMoney)
            {
                npc.value = 0f;
            }
            if (NPCConfig.Instance.NPCNoDrop)
            {
                return !Main.rand.NextBool(2);
            }

            return base.PreKill(npc);
        }
    }
}
